package com.tang.dict;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tang.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.List;

@Slf4j
public abstract class DictFieldParseAble extends ExecutableDictParser {

    ThreadLocal<List<DictParseField>> parserFields = new ThreadLocal<>();

    protected void beforeParse() {
        parserFields.set(CommonUtils.newList());
    }

    protected void afterParse() {
        try {
            while (!CommonUtils.isEmpty(parserFields.get()))
                execute();
        } catch (Exception e) {
            afterException();
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    private void execute() {
        List<DictParseField> dictParseFields = parserFields.get();
        parserFields.set(CommonUtils.newList());
        execute(dictParseFields);
    }

    protected void afterException() {
        parserFields.remove();
    }

    protected void parseFields(Object obj, JSONObject res) {
        Field[] fields = CommonUtils.getAllFields(obj);
        for (Field field : fields) {
            Dict dict = CommonUtils.getAnnotation(field, Dict.class);
            if (CommonUtils.isEmpty(dict)) continue;

            parseField(dict, obj, res, field);
        }
    }

    protected void parseField(Dict dict, Object obj, JSONObject res, Field field) {
        createDictParseField(dict, obj, res, field);
    }

    private void createDictParseField(Dict dict, Object obj, JSONObject res, Field field) {
        DictParseField parseField = null;
        Object fieldValue = res.get(field.getName());
        if(StringUtils.isEmpty(fieldValue)) return;

        switch (dict.type()) {
            case dictCode:
                parseField = createDictCodeParseField(dict, obj, res, field);
                break;
            case dictTable:
                parseField = createDictTableParseField(dict, obj, res, field);
                break;
            case dictObject:
                createDictObjectParseField(dict, obj, res, field);
                break;
            case dictTableObject:
                parseField = createDictTableObjectParseField(dict, obj, res, field);
                break;
        }
        if (!CommonUtils.isEmpty(parseField)) {
            addParseField(parseField);
        }
    }

    private DictParseField createDictTableObjectParseField(Dict dict, Object obj, JSONObject res, Field field) {
        DictParseField dictParseField = new DictParseField() {
            @Override
            public void callback() {
                if (CommonUtils.isEmpty(dictObjects)) return ;
                if (this.resultList) {
                    JSONArray array = new JSONArray();
                    for (Object dictObject : dictObjects) {
                        if (CommonUtils.isEmpty(dictObject)) continue;
                        array.add(doParseDict(dictObjects.get(0)));
                    }
                    res.put(this.getResultField(), array);
                } else {
                    res.put(this.getResultField(), doParseDict(dictObjects.get(0)));
                }
            }
        };
        dictParseField.setDictValue(res.getString(field.getName()));
        dictParseField.setType(DictType.dictTableObject);
        dictParseField.setDictTable(dict.dictTable());
        dictParseField.setDictKeyColumn(dict.dictKeyColumn());
        dictParseField.setResultType(dict.resultType());
        dictParseField.setResultList(dict.resultList());
        dictParseField.setResultField(dict.resultField());
        if (CommonUtils.isEmpty(dictParseField.getResultField())) {
            dictParseField.setResultField(field.getName() + "DictObject");
        }
        dictParseField.check(field);
        return dictParseField;
    }

    private void createDictObjectParseField(Dict dict, Object obj, JSONObject res, Field field) {

        try {
            field.setAccessible(true);
            Object o = field.get(obj);
            if (CommonUtils.isEmpty(o)) return;
            res.put(field.getName(), doParseDict(o));
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private DictParseField createDictTableParseField(Dict dict, Object obj, JSONObject res, Field field) {
        DictParseField dictParseField = new DictParseField() {
            @Override
            public void callback() {
                res.put(this.resultField, this.dictTitle);
            }
        };
        dictParseField.setType(DictType.dictTable);
        dictParseField.setDictValue(res.getString(field.getName()));
        dictParseField.setDictTable(dict.dictTable());
        dictParseField.setDictKeyColumn(dict.dictKeyColumn());
        dictParseField.setDictTitleColumn(dict.dictTitleColumn());
        dictParseField.setDictValue(res.getString(field.getName()));
        dictParseField.setResultField(dict.resultField());
        if (CommonUtils.isEmpty(dictParseField.getResultField())) {
            dictParseField.setResultField(field.getName() + "DictText");
        }
        dictParseField.check(field);
        return dictParseField;
    }

    private DictParseField createDictCodeParseField(Dict dict, Object obj, JSONObject res, Field field) {
        DictParseField dictParseField = new DictParseField() {
            @Override
            public void callback() {
                res.put(this.resultField, this.dictTitle);
            }
        };
        dictParseField.setType(DictType.dictCode);
        dictParseField.setDictCode(dict.dictCode());
        dictParseField.setDictValue(res.getString(field.getName()));
        dictParseField.setResultField(dict.resultField());
        if (CommonUtils.isEmpty(dictParseField.getResultField())) {
            dictParseField.setResultField(field.getName() + "DictText");
        }
        dictParseField.check(field);
        return dictParseField;
    }

    private synchronized void addParseField(DictParseField parseField) {
        parserFields.get().add(parseField);
    }

    @Override
    public List<DictParseField> getParserFields() {
        return parserFields.get();
    }

    @Override
    public void setParserFields(List<DictParseField> fields) {
        parserFields.set(fields);
    }
}
